package com.xishu.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.mongodb.Mongo;
import com.xishu.exception.ResponseStatusException;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FileUtil {
    private static Logger logger = LoggerFactory.getLogger(FileUtil.class);

    public static final String PNG = "png";

    public static final String JPG = "jpg";

    private static List<String> PACKAGES = Arrays.asList("zip", "rar");

    private static final int BLACK = 0xFF000000;

    private static final int WHITE = 0xFFFFFFFF;

    public static String getSuffix(String filename) throws ResponseStatusException {
        String[] split = filename.split("\\.");

        if (ArrayUtils.isEmpty(split)) {
            logger.error("invalide file name is {}", filename);
            throw new ResponseStatusException(ResponseStatus.INVALID_PARAMETER);
        }

        return split[split.length - 1];
    }

    public static String getPrefix(String filename) throws ResponseStatusException {
        String prefix = filename.substring(0, filename.lastIndexOf("."));

        if (StringUtils.isEmpty(prefix)) {
            throw new ResponseStatusException(ResponseStatus.INVALID_PARAMETER);
        }

        return prefix;
    }

    /**
     * 判断是否是压缩包
     *
     * @param fileName
     * @return
     */
    public static boolean isPackageFile(String fileName) throws ResponseStatusException {
        String suffix = getSuffix(fileName);
        return PACKAGES.contains(suffix.toLowerCase());
    }


    /**
     * 拷贝文件
     *
     * @param inputFile
     * @param outFile
     */
    public static void copyFile(File inputFile, File outFile) throws IOException {
        FileCopyUtils.copy(inputFile, outFile);
    }


    /**
     * 删除文件
     *
     * @param file
     */
    public static void deleteFile(File file) {
        try {
            if (file.isFile()) {
                FileUtils.forceDelete(file);
            } else if (file.isDirectory()) {
                FileUtils.deleteDirectory(file);
            }
        } catch (Exception e) {
            logger.error("", e);
        }
    }

    public static String fileType(File file) {
        try {
            if (file.isFile()) {
                return "file";
            } else if (file.isDirectory()) {
                return "dir";
            }
        } catch (Exception e) {
            logger.error("", e);
        }

        return null;
    }

    /**
     * 产生二维码文件图片
     *
     * @param url
     * @return
     */
    public static File createQrCode(String url) {
        try {
            Map<EncodeHintType, String> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

            BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 400, 400, hints);
            File file = MongoId.getInstance().generateTmpFile("jpg");

            if (file.exists() || ((file.getParentFile().exists() || file.getParentFile().mkdirs()) && file.createNewFile())) {
                writeToFile(bitMatrix, "jpg", file);
                logger.info("generate weixin pay file {}", file.getAbsolutePath());
            }

            return file;

        } catch (Exception e) {
            logger.error("e", e);
        }

        return null;
    }

    /**
     * 生成文件
     *
     * @param matrix
     * @param format
     * @param file
     * @throws IOException
     */
    public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format " + format + " to " + file);
        }
    }

    /**
     * 生成图片缓存
     *
     * @param matrix
     * @return
     */
    private static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    /**
     * 写内容到文件
     *
     * @param file
     * @param content
     */
    public static void writeToFile(File file, String content) throws Exception {
        if (!file.exists()) {
            boolean newFile = file.createNewFile();
            VerifyUtil.verify(() -> newFile);
        }

        PrintStream ps = new PrintStream(new FileOutputStream(file));
        ps.println(content);// 往文件里写入字符串
    }

    /**
     * 将文本文件中的内容读入到buffer中
     * @param buffer buffer
     * @param filePath 文件路径
     * @throws IOException 异常
     */
    public static void readToBuffer(StringBuffer buffer, String filePath) throws IOException {
        InputStream is = new FileInputStream(filePath);
        String line; // 用来保存每行读取的内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        line = reader.readLine(); // 读取第一行
        while (line != null) { // 如果 line 为空说明读完了
            buffer.append(line); // 将读到的内容添加到 buffer 中
            buffer.append("\n"); // 添加换行符
            line = reader.readLine(); // 读取下一行
        }
        reader.close();
        is.close();
    }

    /**
     * 读取文本文件内容
     * @param filePath 文件所在路径
     * @return 文本内容
     * @throws IOException 异常
     */
    public static String readFile(String filePath) throws IOException {
        StringBuffer sb = new StringBuffer();
        FileUtil.readToBuffer(sb, filePath);
        return sb.toString();
    }

}
